import tkinter as tk
from tkinter import filedialog, ttk, scrolledtext, messagebox
import exifread
from PIL import Image, ImageTk, ImageDraw, ImageFont
from PIL.ExifTags import TAGS, GPSTAGS
import os
import sys
import json
import xml.etree.ElementTree as ET
from xml.dom import minidom
import datetime
import threading
import webbrowser

class EnhancedExifViewer:
    def __init__(self, root):
        self.root = root
        self.root.title("Enhanced EXIF Viewer v2.0 - 专业级图片信息查看器")
        self.root.geometry("1400x900")
        self.root.minsize(1200, 700)
        
        # 数据存储
        self.current_image_path = None
        self.current_exif_data = {}
        self.gps_coordinates = None
        
        # 设置样式和创建界面
        self.setup_styles()
        self.create_interface()
        
    def setup_styles(self):
        """设置现代化样式"""
        style = ttk.Style()
        
        # 定义颜色主题
        self.colors = {
            'primary': '#2563eb',
            'secondary': '#64748b', 
            'success': '#16a34a',
            'background': '#f8fafc',
            'surface': '#ffffff'
        }
        
        # 配置样式
        style.configure('Header.TLabel', font=('Segoe UI', 12, 'bold'))
        style.configure('Subheader.TLabel', font=('Segoe UI', 10, 'bold'))
        style.configure('Primary.TButton', padding=(10, 5))
        
    def create_interface(self):
        """创建主界面"""
        # 主容器
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 顶部工具栏
        self.create_toolbar(main_frame)
        
        # 主要内容区域 - 使用PanedWindow
        paned = ttk.PanedWindow(main_frame, orient=tk.HORIZONTAL)
        paned.pack(fill=tk.BOTH, expand=True, pady=(10, 0))
        
        # 左侧预览面板
        self.create_preview_panel(paned)
        
        # 右侧信息面板
        self.create_info_panel(paned)
        
        # 底部状态栏
        self.create_status_bar()
        
    def create_toolbar(self, parent):
        """创建工具栏"""
        toolbar = ttk.Frame(parent)
        toolbar.pack(fill=tk.X, pady=(0, 5))
        
        # 文件操作
        file_group = ttk.LabelFrame(toolbar, text="文件操作", padding="5")
        file_group.pack(side=tk.LEFT, padx=(0, 10))
        
        ttk.Button(file_group, text="📁 选择图片", command=self.select_image, 
                  style='Primary.TButton').pack(side=tk.LEFT, padx=(0, 5))
        ttk.Button(file_group, text="🔄 刷新", command=self.refresh_data).pack(side=tk.LEFT)
        
        # 导出操作
        export_group = ttk.LabelFrame(toolbar, text="数据导出", padding="5")
        export_group.pack(side=tk.LEFT, padx=(0, 10))
        
        ttk.Button(export_group, text="JSON", command=self.export_json).pack(side=tk.LEFT, padx=(0, 2))
        ttk.Button(export_group, text="XML", command=self.export_xml).pack(side=tk.LEFT, padx=(0, 2))
        ttk.Button(export_group, text="TXT", command=self.export_txt).pack(side=tk.LEFT)
        
        # 图片处理
        image_group = ttk.LabelFrame(toolbar, text="图片处理", padding="5")
        image_group.pack(side=tk.LEFT)
        
        ttk.Button(image_group, text="🏷️ 添加水印", command=self.add_watermark).pack(side=tk.LEFT)
        
        # 文件信息显示
        info_frame = ttk.Frame(toolbar)
        info_frame.pack(fill=tk.X, padx=(10, 0))
        
        self.file_info_var = tk.StringVar(value="未选择文件")
        ttk.Label(info_frame, textvariable=self.file_info_var, 
                 font=('Segoe UI', 9)).pack(anchor=tk.W)
        
    def create_preview_panel(self, parent):
        """创建预览面板"""
        preview_frame = ttk.Frame(parent, padding="5")
        parent.add(preview_frame, weight=1)
        
        # 预览标签页
        preview_notebook = ttk.Notebook(preview_frame)
        preview_notebook.pack(fill=tk.BOTH, expand=True)
        
        # 原图预览
        original_frame = ttk.Frame(preview_notebook)
        preview_notebook.add(original_frame, text="📷 原图预览")
        
        self.original_canvas = tk.Canvas(original_frame, bg='white')
        self.original_canvas.pack(fill=tk.BOTH, expand=True)
        
        # 水印预览
        watermark_frame = ttk.Frame(preview_notebook)
        preview_notebook.add(watermark_frame, text="🏷️ 水印预览")
        
        self.watermark_canvas = tk.Canvas(watermark_frame, bg='white')
        self.watermark_canvas.pack(fill=tk.BOTH, expand=True)
        
        # 图片基本信息
        self.create_image_summary(preview_frame)
        
    def create_image_summary(self, parent):
        """创建图片摘要信息"""
        summary_frame = ttk.LabelFrame(parent, text="图片摘要", padding="5")
        summary_frame.pack(fill=tk.X, pady=(5, 0))
        
        self.summary_text = tk.Text(summary_frame, height=6, font=('Consolas', 9), 
                                   wrap=tk.WORD, state=tk.DISABLED)
        self.summary_text.pack(fill=tk.X)
        
    def create_info_panel(self, parent):
        """创建信息面板"""
        info_frame = ttk.Frame(parent, padding="5")
        parent.add(info_frame, weight=2)
        
        # 信息标签页
        self.info_notebook = ttk.Notebook(info_frame)
        self.info_notebook.pack(fill=tk.BOTH, expand=True)
        
        # 结构化视图
        self.create_structured_tab()
        
        # 原始数据视图
        self.create_raw_data_tab()
        
        # XML格式视图
        self.create_xml_tab()
        
        # GPS信息视图
        self.create_gps_tab()
        
    def create_structured_tab(self):
        """创建结构化EXIF视图"""
        struct_frame = ttk.Frame(self.info_notebook)
        self.info_notebook.add(struct_frame, text="📊 结构化视图")
        
        # 搜索框
        search_frame = ttk.Frame(struct_frame)
        search_frame.pack(fill=tk.X, pady=(0, 5))
        
        ttk.Label(search_frame, text="🔍 搜索:").pack(side=tk.LEFT)
        self.search_var = tk.StringVar()
        self.search_var.trace('w', self.filter_exif_data)
        ttk.Entry(search_frame, textvariable=self.search_var).pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(5, 0))
        
        # 树形控件
        tree_frame = ttk.Frame(struct_frame)
        tree_frame.pack(fill=tk.BOTH, expand=True)
        
        self.exif_tree = ttk.Treeview(tree_frame, columns=('value', 'description'), show='tree headings')
        self.exif_tree.heading('#0', text='EXIF 标签', anchor=tk.W)
        self.exif_tree.heading('value', text='值', anchor=tk.W)
        self.exif_tree.heading('description', text='描述', anchor=tk.W)
        
        # 设置列宽
        self.exif_tree.column('#0', width=200)
        self.exif_tree.column('value', width=200)
        self.exif_tree.column('description', width=200)
        
        # 滚动条
        tree_scroll = ttk.Scrollbar(tree_frame, orient=tk.VERTICAL, command=self.exif_tree.yview)
        self.exif_tree.configure(yscrollcommand=tree_scroll.set)
        
        self.exif_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        tree_scroll.pack(side=tk.RIGHT, fill=tk.Y)
        
    def create_raw_data_tab(self):
        """创建原始数据视图"""
        raw_frame = ttk.Frame(self.info_notebook)
        self.info_notebook.add(raw_frame, text="📋 原始数据")
        
        self.raw_text = scrolledtext.ScrolledText(raw_frame, font=('Consolas', 9))
        self.raw_text.pack(fill=tk.BOTH, expand=True)
        
    def create_xml_tab(self):
        """创建XML视图"""
        xml_frame = ttk.Frame(self.info_notebook)
        self.info_notebook.add(xml_frame, text="📄 XML格式")
        
        self.xml_text = scrolledtext.ScrolledText(xml_frame, font=('Consolas', 9))
        self.xml_text.pack(fill=tk.BOTH, expand=True)
        
    def create_gps_tab(self):
        """创建GPS视图"""
        gps_frame = ttk.Frame(self.info_notebook)
        self.info_notebook.add(gps_frame, text="🌍 GPS信息")
        
        # GPS信息显示
        gps_info_frame = ttk.LabelFrame(gps_frame, text="定位信息", padding="10")
        gps_info_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        self.gps_text = scrolledtext.ScrolledText(gps_info_frame, height=15, font=('Consolas', 9))
        self.gps_text.pack(fill=tk.BOTH, expand=True)
        
        # 地图按钮
        map_frame = ttk.Frame(gps_frame)
        map_frame.pack(fill=tk.X, padx=5, pady=5)
        
        self.map_button = ttk.Button(map_frame, text="🗺️ 在Google地图中查看", 
                                   command=self.open_in_map, state=tk.DISABLED)
        self.map_button.pack(side=tk.LEFT)
        
    def create_status_bar(self):
        """创建状态栏"""
        status_frame = ttk.Frame(self.root)
        status_frame.pack(fill=tk.X, side=tk.BOTTOM)
        
        self.status_var = tk.StringVar(value="就绪 - 请选择图片文件")
        ttk.Label(status_frame, textvariable=self.status_var).pack(side=tk.LEFT, padx=5, pady=2)
        
        self.progress = ttk.Progressbar(status_frame, mode='indeterminate')
        self.progress.pack(side=tk.RIGHT, padx=5, pady=2)

    def select_image(self):
        """选择图片文件"""
        file_path = filedialog.askopenfilename(
            title="选择图片文件",
            filetypes=[
                ("图片文件", "*.jpg *.jpeg *.png *.gif *.bmp *.tiff *.tif *.webp *.heic"),
                ("JPEG文件", "*.jpg *.jpeg"),
                ("PNG文件", "*.png"),
                ("TIFF文件", "*.tiff *.tif"),
                ("所有文件", "*.*")
            ]
        )
        
        if file_path:
            self.load_image(file_path)
            
    def load_image(self, file_path):
        """加载并解析图片"""
        self.current_image_path = file_path
        filename = os.path.basename(file_path)
        self.file_info_var.set(f"📁 {filename}")
        
        # 开始处理
        self.progress.start()
        self.status_var.set("正在解析图片EXIF信息...")
        
        def process():
            try:
                self.parse_comprehensive_exif(file_path)
                self.root.after(0, self.update_all_views)
            except Exception as e:
                self.root.after(0, lambda: self.show_error(f"处理失败: {str(e)}"))
                
        threading.Thread(target=process, daemon=True).start()

    def parse_comprehensive_exif(self, file_path):
        """全面解析EXIF信息"""
        self.current_exif_data = {
            'file_info': {},
            'image_info': {},
            'exif_tags': {},
            'gps_info': {},
            'raw_exif': {}
        }
        
        # 文件信息
        stat = os.stat(file_path)
        self.current_exif_data['file_info'] = {
            '文件名': os.path.basename(file_path),
            '文件大小': f"{stat.st_size / 1024 / 1024:.2f} MB",
            '创建时间': datetime.datetime.fromtimestamp(stat.st_ctime).strftime('%Y-%m-%d %H:%M:%S'),
            '修改时间': datetime.datetime.fromtimestamp(stat.st_mtime).strftime('%Y-%m-%d %H:%M:%S'),
            '完整路径': file_path
        }
        
        # 使用PIL解析
        try:
            with Image.open(file_path) as img:
                self.current_exif_data['image_info'] = {
                    '图片尺寸': f"{img.width} x {img.height}",
                    '颜色模式': img.mode,
                    '图片格式': img.format,
                    '色彩深度': f"{len(img.getbands())} 通道"
                }
                
                # PIL EXIF数据
                if hasattr(img, '_getexif') and img._getexif():
                    exif_data = img._getexif()
                    for tag_id, value in exif_data.items():
                        tag_name = TAGS.get(tag_id, f"Unknown_{tag_id}")
                        
                        if tag_name == 'GPSInfo':
                            gps_data = {}
                            for gps_tag_id, gps_value in value.items():
                                gps_tag_name = GPSTAGS.get(gps_tag_id, f"GPS_Unknown_{gps_tag_id}")
                                gps_data[gps_tag_name] = gps_value
                            self.current_exif_data['gps_info'] = gps_data
                        else:
                            if isinstance(value, bytes):
                                try:
                                    value = value.decode('utf-8', errors='ignore')
                                except:
                                    value = repr(value)
                            self.current_exif_data['exif_tags'][tag_name] = value
        except Exception as e:
            print(f"PIL解析错误: {e}")
            
        # 使用exifread解析详细信息
        try:
            with open(file_path, 'rb') as f:
                tags = exifread.process_file(f, details=True)
                for tag, value in tags.items():
                    self.current_exif_data['raw_exif'][tag] = str(value)
        except Exception as e:
            print(f"ExifRead解析错误: {e}")

    def update_all_views(self):
        """更新所有视图"""
        try:
            self.progress.stop()
            
            self.update_tree_view()
            self.update_raw_view()
            self.update_xml_view()
            self.update_gps_view()
            self.update_preview()
            self.update_summary()
            
            self.status_var.set(f"✓ 已加载: {os.path.basename(self.current_image_path)}")
            
        except Exception as e:
            self.show_error(f"更新视图失败: {str(e)}")

    def update_tree_view(self):
        """更新树形视图"""
        # 清空
        for item in self.exif_tree.get_children():
            self.exif_tree.delete(item)
            
        # 添加文件信息
        if self.current_exif_data['file_info']:
            file_node = self.exif_tree.insert('', 'end', text='📁 文件信息', open=True)
            for key, value in self.current_exif_data['file_info'].items():
                self.exif_tree.insert(file_node, 'end', text=key, values=(str(value), ''))
                
        # 添加图片信息
        if self.current_exif_data['image_info']:
            img_node = self.exif_tree.insert('', 'end', text='🖼️ 图片信息', open=True)
            for key, value in self.current_exif_data['image_info'].items():
                self.exif_tree.insert(img_node, 'end', text=key, values=(str(value), ''))
                
        # 添加EXIF标签
        if self.current_exif_data['exif_tags']:
            exif_node = self.exif_tree.insert('', 'end', text='📷 EXIF标签', open=True)
            for key, value in sorted(self.current_exif_data['exif_tags'].items()):
                desc = self.get_exif_description(key)
                self.exif_tree.insert(exif_node, 'end', text=key, values=(str(value), desc))
                
        # 添加GPS信息
        if self.current_exif_data['gps_info']:
            gps_node = self.exif_tree.insert('', 'end', text='🌍 GPS信息', open=True)
            for key, value in self.current_exif_data['gps_info'].items():
                self.exif_tree.insert(gps_node, 'end', text=key, values=(str(value), ''))

    def update_raw_view(self):
        """更新原始数据视图"""
        self.raw_text.delete(1.0, tk.END)
        
        content = "=== 完整EXIF原始数据 ===\\n\\n"
        for tag, value in sorted(self.current_exif_data['raw_exif'].items()):
            content += f"{tag}: {value}\\n"
            
        self.raw_text.insert(1.0, content)

    def update_xml_view(self):
        """更新XML视图"""
        self.xml_text.delete(1.0, tk.END)
        
        try:
            root = ET.Element('ExifData')
            root.set('file', os.path.basename(self.current_image_path))
            root.set('timestamp', datetime.datetime.now().isoformat())
            
            # 添加各类信息
            for category, data in self.current_exif_data.items():
                if data and category != 'raw_exif':
                    cat_elem = ET.SubElement(root, category.replace('_', '').title())
                    for key, value in data.items():
                        item_elem = ET.SubElement(cat_elem, 'Item')
                        item_elem.set('name', key)
                        item_elem.text = str(value)
                        
            # 格式化输出
            rough_string = ET.tostring(root, 'unicode')
            reparsed = minidom.parseString(rough_string)
            self.xml_text.insert(1.0, reparsed.toprettyxml(indent="  "))
            
        except Exception as e:
            self.xml_text.insert(1.0, f"XML生成失败: {str(e)}")

    def update_gps_view(self):
        """更新GPS视图"""
        self.gps_text.delete(1.0, tk.END)
        
        if self.current_exif_data['gps_info']:
            content = "=== GPS定位信息 ===\\n\\n"
            
            # 解析坐标
            lat, lon = self.parse_gps_coordinates()
            if lat and lon:
                content += f"纬度: {lat:.6f}°\\n"
                content += f"经度: {lon:.6f}°\\n"
                content += f"Google Maps: {lat},{lon}\\n\\n"
                self.gps_coordinates = (lat, lon)
                self.map_button.config(state=tk.NORMAL)
            else:
                content += "坐标解析失败\\n\\n"
                self.map_button.config(state=tk.DISABLED)
                
            # 显示所有GPS数据
            for key, value in self.current_exif_data['gps_info'].items():
                content += f"{key}: {value}\\n"
        else:
            content = "该图片不包含GPS定位信息"
            self.map_button.config(state=tk.DISABLED)
            
        self.gps_text.insert(1.0, content)

    def parse_gps_coordinates(self):
        """解析GPS坐标"""
        try:
            gps = self.current_exif_data['gps_info']
            if not gps:
                return None, None
                
            # 解析纬度
            lat = None
            if 'GPSLatitude' in gps and 'GPSLatitudeRef' in gps:
                lat_data = gps['GPSLatitude']
                lat_ref = gps['GPSLatitudeRef']
                if isinstance(lat_data, (list, tuple)) and len(lat_data) >= 3:
                    lat = float(lat_data[0]) + float(lat_data[1])/60 + float(lat_data[2])/3600
                    if lat_ref == 'S':
                        lat = -lat
                        
            # 解析经度
            lon = None
            if 'GPSLongitude' in gps and 'GPSLongitudeRef' in gps:
                lon_data = gps['GPSLongitude']
                lon_ref = gps['GPSLongitudeRef']
                if isinstance(lon_data, (list, tuple)) and len(lon_data) >= 3:
                    lon = float(lon_data[0]) + float(lon_data[1])/60 + float(lon_data[2])/3600
                    if lon_ref == 'W':
                        lon = -lon
                        
            return lat, lon
        except:
            return None, None

    def update_preview(self):
        """更新图片预览"""
        if not self.current_image_path:
            return
            
        try:
            # 原图预览
            img = Image.open(self.current_image_path)
            
            # 计算合适的显示尺寸
            canvas_width = self.original_canvas.winfo_width()
            canvas_height = self.original_canvas.winfo_height()
            
            if canvas_width <= 1 or canvas_height <= 1:
                # 如果canvas还没有正确的尺寸，延迟更新
                self.root.after(100, self.update_preview)
                return
                
            img_ratio = img.width / img.height
            canvas_ratio = canvas_width / canvas_height
            
            if img_ratio > canvas_ratio:
                new_width = min(canvas_width - 20, img.width)
                new_height = int(new_width / img_ratio)
            else:
                new_height = min(canvas_height - 20, img.height)
                new_width = int(new_height * img_ratio)
                
            img_resized = img.resize((new_width, new_height), Image.Resampling.LANCZOS)
            self.photo = ImageTk.PhotoImage(img_resized)
            
            self.original_canvas.delete("all")
            x = (canvas_width - new_width) // 2
            y = (canvas_height - new_height) // 2
            self.original_canvas.create_image(x, y, anchor=tk.NW, image=self.photo)
            
            # 水印预览
            self.update_watermark_preview(img_resized)
            
        except Exception as e:
            print(f"预览更新失败: {e}")

    def update_watermark_preview(self, img):
        """更新水印预览"""
        try:
            # 创建水印
            watermarked = img.copy().convert("RGBA")
            draw = ImageDraw.Draw(watermarked)
            
            # 获取设备信息
            make = self.current_exif_data['exif_tags'].get('Make', 'Unknown')
            model = self.current_exif_data['exif_tags'].get('Model', 'Camera')
            
            # 获取拍摄时间
            date_taken = (self.current_exif_data['exif_tags'].get('DateTimeOriginal') or 
                         self.current_exif_data['exif_tags'].get('DateTime', 'Unknown Date'))
            
            # 水印文本
            watermark_text = f"{make} {model}\\n{date_taken}"
            
            # 字体设置
            font_size = max(12, min(watermarked.width, watermarked.height) // 30)
            try:
                font = ImageFont.truetype("arial.ttf", font_size)
            except:
                font = ImageFont.load_default()
                
            # 水印位置（左下角）
            margin = 10
            lines = watermark_text.split('\\n')
            
            # 计算文本总高度
            total_height = len(lines) * font_size * 1.2
            y = watermarked.height - total_height - margin
            
            # 绘制水印
            for i, line in enumerate(lines):
                line_y = y + i * font_size * 1.2
                # 阴影
                draw.text((margin + 1, line_y + 1), line, font=font, fill=(0, 0, 0, 128))
                # 主文本
                draw.text((margin, line_y), line, font=font, fill=(255, 255, 255, 200))
                
            self.watermark_photo = ImageTk.PhotoImage(watermarked)
            
            self.watermark_canvas.delete("all")
            canvas_width = self.watermark_canvas.winfo_width()
            canvas_height = self.watermark_canvas.winfo_height()
            x = (canvas_width - watermarked.width) // 2
            y = (canvas_height - watermarked.height) // 2
            self.watermark_canvas.create_image(x, y, anchor=tk.NW, image=self.watermark_photo)
            
        except Exception as e:
            print(f"水印预览失败: {e}")

    def update_summary(self):
        """更新图片摘要"""
        self.summary_text.config(state=tk.NORMAL)
        self.summary_text.delete(1.0, tk.END)
        
        if self.current_exif_data:
            summary = []
            
            # 基本信息
            file_info = self.current_exif_data.get('file_info', {})
            img_info = self.current_exif_data.get('image_info', {})
            exif_info = self.current_exif_data.get('exif_tags', {})
            
            if file_info.get('文件大小'):
                summary.append(f"文件大小: {file_info['文件大小']}")
            if img_info.get('图片尺寸'):
                summary.append(f"尺寸: {img_info['图片尺寸']}")
            if img_info.get('图片格式'):
                summary.append(f"格式: {img_info['图片格式']}")
                
            # 相机信息
            camera_info = []
            if exif_info.get('Make'):
                camera_info.append(exif_info['Make'])
            if exif_info.get('Model'):
                camera_info.append(exif_info['Model'])
            if camera_info:
                summary.append(f"相机: {' '.join(camera_info)}")
                
            # 拍摄参数
            if exif_info.get('FNumber'):
                summary.append(f"光圈: f/{exif_info['FNumber']}")
            if exif_info.get('ExposureTime'):
                summary.append(f"快门: {exif_info['ExposureTime']}s")
            if exif_info.get('ISOSpeedRatings'):
                summary.append(f"ISO: {exif_info['ISOSpeedRatings']}")
            if exif_info.get('FocalLength'):
                summary.append(f"焦距: {exif_info['FocalLength']}mm")
                
            # 拍摄时间
            if exif_info.get('DateTimeOriginal'):
                summary.append(f"拍摄时间: {exif_info['DateTimeOriginal']}")
                
            # GPS信息
            if self.current_exif_data.get('gps_info'):
                summary.append("包含GPS定位信息")
                
            self.summary_text.insert(1.0, '\\n'.join(summary))
            
        self.summary_text.config(state=tk.DISABLED)

    # 辅助方法
    def get_exif_description(self, tag_name):
        """获取EXIF标签描述"""
        descriptions = {
            'Make': '相机制造商',
            'Model': '相机型号',
            'DateTimeOriginal': '拍摄时间',
            'FNumber': '光圈值',
            'ExposureTime': '曝光时间',
            'ISOSpeedRatings': 'ISO感光度',
            'FocalLength': '焦距',
            'Flash': '闪光灯',
            'WhiteBalance': '白平衡',
            'ExposureMode': '曝光模式',
            'SceneCaptureType': '场景类型'
        }
        return descriptions.get(tag_name, '')

    def filter_exif_data(self, *args):
        """过滤EXIF数据"""
        search_term = self.search_var.get().lower()
        if not search_term:
            # 如果搜索框为空，显示所有项目
            for item in self.exif_tree.get_children():
                self.show_tree_item(item, True)
        else:
            # 过滤项目
            for item in self.exif_tree.get_children():
                self.filter_tree_item(item, search_term)

    def filter_tree_item(self, item, search_term):
        """递归过滤树形项目"""
        text = self.exif_tree.item(item, 'text').lower()
        values = ' '.join(str(v).lower() for v in self.exif_tree.item(item, 'values'))
        
        # 检查当前项目是否匹配
        matches = search_term in text or search_term in values
        
        # 检查子项目
        children = self.exif_tree.get_children(item)
        child_matches = False
        for child in children:
            if self.filter_tree_item(child, search_term):
                child_matches = True
                
        show = matches or child_matches
        self.show_tree_item(item, show)
        return show

    def show_tree_item(self, item, show):
        """显示或隐藏树形项目"""
        if show:
            self.exif_tree.reattach(item, '', 'end')
        else:
            self.exif_tree.detach(item)

    def refresh_data(self):
        """刷新数据"""
        if self.current_image_path:
            self.load_image(self.current_image_path)

    def export_json(self):
        """导出JSON格式"""
        if not self.current_exif_data:
            messagebox.showwarning("警告", "没有可导出的数据")
            return
            
        file_path = filedialog.asksaveasfilename(
            defaultextension=".json",
            filetypes=[("JSON文件", "*.json")],
            title="导出JSON格式EXIF数据"
        )
        
        if file_path:
            try:
                with open(file_path, 'w', encoding='utf-8') as f:
                    json.dump(self.current_exif_data, f, ensure_ascii=False, indent=2)
                messagebox.showinfo("成功", f"数据已导出到: {file_path}")
            except Exception as e:
                messagebox.showerror("错误", f"导出失败: {str(e)}")

    def export_xml(self):
        """导出XML格式"""
        if not self.current_exif_data:
            messagebox.showwarning("警告", "没有可导出的数据")
            return
            
        file_path = filedialog.asksaveasfilename(
            defaultextension=".xml",
            filetypes=[("XML文件", "*.xml")],
            title="导出XML格式EXIF数据"
        )
        
        if file_path:
            try:
                with open(file_path, 'w', encoding='utf-8') as f:
                    f.write(self.xml_text.get(1.0, tk.END))
                messagebox.showinfo("成功", f"数据已导出到: {file_path}")
            except Exception as e:
                messagebox.showerror("错误", f"导出失败: {str(e)}")

    def export_txt(self):
        """导出TXT格式"""
        if not self.current_exif_data:
            messagebox.showwarning("警告", "没有可导出的数据")
            return
            
        file_path = filedialog.asksaveasfilename(
            defaultextension=".txt",
            filetypes=[("文本文件", "*.txt")],
            title="导出文本格式EXIF数据"
        )
        
        if file_path:
            try:
                with open(file_path, 'w', encoding='utf-8') as f:
                    f.write(self.raw_text.get(1.0, tk.END))
                messagebox.showinfo("成功", f"数据已导出到: {file_path}")
            except Exception as e:
                messagebox.showerror("错误", f"导出失败: {str(e)}")

    def add_watermark(self):
        """添加水印到图片"""
        if not self.current_image_path:
            messagebox.showwarning("警告", "请先选择图片")
            return
            
        output_path = filedialog.asksaveasfilename(
            defaultextension=".jpg",
            filetypes=[
                ("JPEG图片", "*.jpg"),
                ("PNG图片", "*.png"),
                ("所有文件", "*.*")
            ],
            title="保存水印图片"
        )
        
        if output_path:
            try:
                # 加载原图
                img = Image.open(self.current_image_path).convert("RGBA")
                draw = ImageDraw.Draw(img)
                
                # 获取设备信息
                make = self.current_exif_data['exif_tags'].get('Make', 'Unknown')
                model = self.current_exif_data['exif_tags'].get('Model', 'Camera')
                date_taken = (self.current_exif_data['exif_tags'].get('DateTimeOriginal') or 
                             self.current_exif_data['exif_tags'].get('DateTime', 'Unknown Date'))
                
                # 水印文本
                watermark_text = f"{make} {model}\\n{date_taken}"
                
                # 字体设置
                font_size = max(20, min(img.width, img.height) // 40)
                try:
                    font = ImageFont.truetype("arial.ttf", font_size)
                except:
                    font = ImageFont.load_default()
                    
                # 水印位置（左下角）
                margin = 20
                lines = watermark_text.split('\\n')
                
                total_height = len(lines) * font_size * 1.2
                y = img.height - total_height - margin
                
                # 绘制水印
                for i, line in enumerate(lines):
                    line_y = y + i * font_size * 1.2
                    # 阴影
                    draw.text((margin + 2, line_y + 2), line, font=font, fill=(0, 0, 0, 128))
                    # 主文本
                    draw.text((margin, line_y), line, font=font, fill=(255, 255, 255, 200))
                    
                # 保存
                img.convert("RGB").save(output_path, quality=95)
                messagebox.showinfo("成功", f"水印图片已保存到: {output_path}")
                
            except Exception as e:
                messagebox.showerror("错误", f"添加水印失败: {str(e)}")

    def open_in_map(self):
        """在地图中查看GPS位置"""
        if self.gps_coordinates:
            lat, lon = self.gps_coordinates
            url = f"https://www.google.com/maps?q={lat},{lon}"
            webbrowser.open(url)

    def show_error(self, message):
        """显示错误信息"""
        self.progress.stop()
        self.status_var.set(f"错误: {message}")
        messagebox.showerror("错误", message)

def main():
    """主函数"""
    try:
        import exifread
        from PIL import Image, ImageTk
    except ImportError as e:
        print(f"缺少必要的库: {e}")
        print("请运行: pip install exifread Pillow")
        sys.exit(1)
    
    root = tk.Tk()
    app = EnhancedExifViewer(root)
    root.mainloop()

if __name__ == '__main__':
    main()